<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>12-getSnapshotBeforeUpdate</title>
    <script src="lib/react/react.development.js"></script>
    <script src="lib/react/react-dom.development.js"></script>
    <script src="lib/babel.min.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .ul-chat {
        width: 200px;
        height: 200px;
        border: 1px solid red;
        margin: 30px;
        overflow: auto;
      }
      .ul-chat > li {
        height: 30px;
        font-size: 20px;
        line-height: 30px;
        text-indent: 2em;
      }
    </style>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">
      class HelloWorld extends React.Component {
        constructor(props) {
          super(props);
          console.log("constructor....");
          // 创建ref
          this.chatUlRef = React.createRef();
          this.state = {
            chatItems: [
              {
                id: 1,
                text: "吃了么",
              },
              {
                id: 2,
                text: "吃了!",
              },
              {
                id: 3,
                text: "吃啥了?",
              },
              {
                id: 4,
                text: "吃好吃的!",
              },
            ],
          };
          // bind
          this.handleKeyUp = this.handleKeyUp.bind(this);
        }

        componentDidMount() {}
        // 在state被更新后触发,而又没来得及更新到UI的时候
        // 这里可以获取到更新之前的UI状态,比如滚轮位置
        // prevState 上一次的state
        // 此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()。
        getSnapshotBeforeUpdate(prevProps, prevState) {
          // 1. 得到之前容器的高度
          // 注意: 必须是等内容高度发生变化的时候再处理
          if (this.state.chatItems.length > prevState.chatItems.length) {
            // 这里没来得及更新UI,所以得到的是上一次更新后的DOM
            var chatUl = this.chatUlRef.current;
            // 之前的容器内容高度
            var preContentHeight = chatUl.scrollHeight - chatUl.scrollTop;
            return preContentHeight;
          }
          // 如果聊天列表高度没变化,则返回null
          return null;
        }
        // snapshot 是通过getSnapshotBeforeUpdate声明周期函数返回的
        componentDidUpdate(prevProps, prevState, snapshot) {
          console.log("didUpdate....", this.state);
          console.log("snapshot", snapshot);
          // 2. 用更新后的最新高度 - 原来的内容高度 得到的就是需要被卷进去的高度
          if (snapshot) {
            var chatUl = this.chatUlRef.current;
            // 计算需要被卷入的高度(多余的高度)
            var useScrollTop = chatUl.scrollHeight - snapshot;
            // 3. 赋值
            chatUl.scrollTop = useScrollTop;
          }
        }
        // 如果是输入了enter,需要把最新文本内容 更新到state.chatItems
        handleKeyUp(e) {
          // keyCode 可以获取键盘按键的 Ascii编码值
          var keyCode = e.keyCode;
          // 如果值== 13 说明是enter键
          if (keyCode == 13) {
            // 获取input的value
            // 不能直接修改state的值,必须通过setState才能触发render()!!!
            // 所以如果state的某个值是对象类型,需要先克隆
            // [...xxx] 数组结构
            var chatItems = [...this.state.chatItems];
            chatItems.push({
              id: new Date().getTime(), // 时间戳肯定不同
              text: e.target.value,
            });
            // 用setState更新
            this.setState({
              chatItems,
            });
            // 更新后还原输入框
            e.target.value = "";
          }
        }
        render() {
          console.log("render....", this.state);
          var liItems = this.state.chatItems.map((item) => (
            <li key={item.id}>{item.text}</li>
          ));
          return (
            <div>
              <input
                type="text"
                onKeyUp={this.handleKeyUp}
                placeholder="请输入聊天内容"
              />
              <ul className="ul-chat" ref={this.chatUlRef}>
                {liItems}
              </ul>
            </div>
          );
        }
      }
      // 使用react 相关api 渲染到容器
      ReactDOM.render(<HelloWorld />, document.getElementById("root"));
    </script>
  </body>
</html>
